package org.zn.note.designpattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 服务定位器模式（Service Locator Pattern）
 * <p>
 * 服务（Service） - 实际处理请求的服务。对这种服务的引用可以在 JNDI 服务器中查找到。
 * Context / 初始的 Context - JNDI Context 带有对要查找的服务的引用。
 * 服务定位器（Service Locator） - 服务定位器是通过 JNDI 查找和缓存服务来获取服务的单点接触。
 * 缓存（Cache） - 缓存存储服务的引用，以便复用它们。
 * 客户端（Client） - Client 是通过 ServiceLocator 调用服务的对象。
 */
public class Pattern32_ServiceLocator {

    public static void main(String[] args) {
        Service service = ServiceLocator.getService("Service1");
        service.execute();
        service = ServiceLocator.getService("Service2");
        service.execute();
        service = ServiceLocator.getService("Service1");
        service.execute();
        service = ServiceLocator.getService("Service2");
        service.execute();
    }

    private interface Service {
        String getName();

        void execute();
    }

    private static class Service1 implements Service {
        public void execute() {
            System.out.println("Executing Service1");
        }

        @Override
        public String getName() {
            return "Service1";
        }
    }

    private static class Service2 implements Service {
        public void execute() {
            System.out.println("Executing Service2");
        }

        @Override
        public String getName() {
            return "Service2";
        }
    }

    private static class InitialContext {
        Object lookup(String jndiName) {
            if (jndiName.equalsIgnoreCase("SERVICE1")) {
                System.out.println("Looking up and creating a new Service1 object");
                return new Service1();
            } else if (jndiName.equalsIgnoreCase("SERVICE2")) {
                System.out.println("Looking up and creating a new Service2 object");
                return new Service2();
            }
            return null;
        }
    }

    private static class Cache {

        private List<Service> services;

        Cache() {
            services = new ArrayList<Service>();
        }

        Service getService(String serviceName) {
            for (Service service : services) {
                if (service.getName().equalsIgnoreCase(serviceName)) {
                    System.out.println("Returning cached  " + serviceName + " object");
                    return service;
                }
            }
            return null;
        }

        void addService(Service newService) {
            boolean exists = false;
            for (Service service : services) {
                if (service.getName().equalsIgnoreCase(newService.getName())) {
                    exists = true;
                }
            }
            if (!exists) {
                services.add(newService);
            }
        }
    }

    private static class ServiceLocator {
        private static Cache cache;

        static {
            cache = new Cache();
        }

        static Service getService(String jndiName) {

            Service service = cache.getService(jndiName);

            if (service != null) {
                return service;
            }

            InitialContext context = new InitialContext();
            Service service1 = (Service) context.lookup(jndiName);
            cache.addService(service1);
            return service1;
        }
    }
}
